Explorez Tornado, le framework web Python asynchrone. Créez des applications évolutives et performantes avec nos explications, exemples et bonnes pratiques.
Documentation Tornado : Un Guide Complet pour les Développeurs du Monde Entier
Tornado est un framework web Python et une bibliothĂšque de rĂ©seau asynchrone, initialement dĂ©veloppĂ© chez FriendFeed. Il est particuliĂšrement adaptĂ© au long-polling, aux WebSockets et Ă d'autres applications qui nĂ©cessitent une connexion de longue durĂ©e avec chaque utilisateur. Ses E/S rĂ©seau non bloquantes le rendent extrĂȘmement Ă©volutif et un choix puissant pour crĂ©er des applications web haute performance. Ce guide complet vous prĂ©sentera les concepts fondamentaux de Tornado et fournira des exemples pratiques pour vous aider Ă dĂ©marrer.
Qu'est-ce que Tornado ?
Au cĆur de sa conception, Tornado est un framework web et une bibliothĂšque de rĂ©seau asynchrone. Contrairement aux frameworks web synchrones traditionnels, Tornado utilise une architecture mono-thread basĂ©e sur une boucle d'Ă©vĂ©nements. Cela signifie qu'il peut gĂ©rer de nombreuses connexions simultanĂ©es sans nĂ©cessiter un thread par connexion, ce qui le rend plus efficace et Ă©volutif.
Caractéristiques Clés de Tornado :
- RĂ©seau Asynchrone : Le cĆur de Tornado est construit autour des E/S asynchrones, lui permettant de gĂ©rer efficacement des milliers de connexions simultanĂ©es.
- Framework Web : Il inclut des fonctionnalitĂ©s comme les gestionnaires de requĂȘtes, le routage, les modĂšles (templating) et l'authentification, ce qui en fait un framework web complet.
- Support des WebSockets : Tornado offre un excellent support pour les WebSockets, permettant une communication en temps réel entre le serveur et les clients.
- Léger et Rapide : Conçu pour la performance, Tornado est léger et efficace, minimisant la surcharge et maximisant le débit.
- Facile à Utiliser : Malgré ses fonctionnalités avancées, Tornado est relativement facile à apprendre et à utiliser, avec une API claire et bien documentée.
Configurer Votre Environnement Tornado
Avant de plonger dans le développement avec Tornado, vous devez configurer votre environnement. Voici un guide étape par étape :
- Installer Python : Assurez-vous d'avoir Python 3.6 ou une version ultérieure d'installé. Vous pouvez le télécharger depuis le site officiel de Python (python.org).
- Créer un Environnement Virtuel (Recommandé) : Utilisez
venvouvirtualenvpour créer un environnement isolé pour votre projet :python3 -m venv myenv source myenv/bin/activate # Sur Linux/macOS myenv\Scripts\activate # Sur Windows - Installer Tornado : Installez Tornado en utilisant pip :
pip install tornado
Votre PremiĂšre Application Tornado
Créons une simple application "Hello, World!" avec Tornado. Créez un fichier nommé app.py et ajoutez le code suivant :
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, World!")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
Maintenant, exécutez l'application depuis votre terminal :
python app.py
Ouvrez votre navigateur web et naviguez vers http://localhost:8888. Vous devriez voir le message "Hello, World!".
Explication :
tornado.ioloop: La boucle d'Ă©vĂ©nements principale qui gĂšre les opĂ©rations asynchrones.tornado.web: Fournit les composants du framework web, tels que les gestionnaires de requĂȘtes et le routage.MainHandler: Un gestionnaire de requĂȘtes qui dĂ©finit comment traiter les requĂȘtes HTTP entrantes. La mĂ©thodeget()est appelĂ©e pour les requĂȘtes GET.tornado.web.Application: CrĂ©e l'application Tornado, en associant des modĂšles d'URL aux gestionnaires de requĂȘtes.app.listen(8888): DĂ©marre le serveur, en Ă©coutant les connexions entrantes sur le port 8888.tornado.ioloop.IOLoop.current().start(): DĂ©marre la boucle d'Ă©vĂ©nements, qui traite les requĂȘtes entrantes et gĂšre les opĂ©rations asynchrones.
Gestionnaires de RequĂȘtes et Routage
Les gestionnaires de requĂȘtes sont le fondement des applications web Tornado. Ils dĂ©finissent comment traiter les requĂȘtes HTTP entrantes en fonction de l'URL. Le routage associe les URL Ă des gestionnaires de requĂȘtes spĂ©cifiques.
DĂ©finir les Gestionnaires de RequĂȘtes :
Pour crĂ©er un gestionnaire de requĂȘtes, hĂ©ritez de la classe tornado.web.RequestHandler et implĂ©mentez les mĂ©thodes HTTP appropriĂ©es (get, post, put, delete, etc.).
class MyHandler(tornado.web.RequestHandler):
def get(self):
self.write("Ceci est une requĂȘte GET.")
def post(self):
data = self.request.body.decode('utf-8')
self.write(f"Données POST reçues : {data}")
Routage :
Le routage est configurĂ© lors de la crĂ©ation de l'objet tornado.web.Application. Vous fournissez une liste de tuples, oĂč chaque tuple contient un modĂšle d'URL et le gestionnaire de requĂȘtes correspondant.
app = tornado.web.Application([
(r"/", MainHandler),
(r"/myhandler", MyHandler),
])
ModĂšles d'URL :
Les modĂšles d'URL sont des expressions rĂ©guliĂšres. Vous pouvez utiliser des groupes d'expressions rĂ©guliĂšres pour capturer des parties de l'URL et les passer comme arguments aux mĂ©thodes du gestionnaire de requĂȘtes.
class UserHandler(tornado.web.RequestHandler):
def get(self, user_id):
self.write(f"ID Utilisateur : {user_id}")
app = tornado.web.Application([
(r"/user/([0-9]+)", UserHandler),
])
Dans cet exemple, /user/([0-9]+) correspond à des URL comme /user/123. La partie ([0-9]+) capture un ou plusieurs chiffres et les passe comme argument user_id à la méthode get du UserHandler.
ModĂšles (Templating)
Tornado inclut un moteur de modÚles simple et efficace. Les modÚles sont utilisés pour générer du HTML dynamiquement, séparant la logique de présentation de la logique applicative.
Créer des ModÚles :
Les modÚles sont généralement stockés dans des fichiers séparés (par ex., index.html). Voici un exemple simple :
<!DOCTYPE html>
<html>
<head>
<title>Mon Site Web</title>
</head>
<body>
<h1>Bienvenue, {{ name }} !</h1>
<p>Aujourd'hui, nous sommes le {{ today }}.</p>
</body>
</html>
Les {{ name }} et {{ today }} sont des balises de remplacement qui seront remplacées par des valeurs réelles lors du rendu du modÚle.
Rendu des ModĂšles :
Pour effectuer le rendu d'un modĂšle, utilisez la mĂ©thode render() dans votre gestionnaire de requĂȘtes :
class TemplateHandler(tornado.web.RequestHandler):
def get(self):
name = "John Doe"
today = "2023-10-27"
self.render("index.html", name=name, today=today)
Assurez-vous que le paramĂštre template_path est correctement configurĂ© dans les paramĂštres de votre application. Par dĂ©faut, Tornado recherche les modĂšles dans un rĂ©pertoire nommĂ© templates situĂ© dans le mĂȘme rĂ©pertoire que votre fichier d'application.
app = tornado.web.Application([
(r"/template", TemplateHandler),
], template_path="templates")
Syntaxe des ModĂšles :
Les modÚles Tornado prennent en charge diverses fonctionnalités, notamment :
- Variables :
{{ variable }} - Flux de ContrĂŽle :
{% if condition %} ... {% else %} ... {% end %},{% for item in items %} ... {% end %} - Fonctions :
{{ function(argument) }} - Inclusions :
{% include "another_template.html" %} - Ăchappement : Tornado Ă©chappe automatiquement les entitĂ©s HTML pour prĂ©venir les attaques de type cross-site scripting (XSS). Vous pouvez dĂ©sactiver l'Ă©chappement en utilisant
{% raw variable %}.
Opérations Asynchrones
La force de Tornado rĂ©side dans ses capacitĂ©s asynchrones. Les opĂ©rations asynchrones permettent Ă votre application d'effectuer des E/S non bloquantes, amĂ©liorant ainsi les performances et la scalabilitĂ©. C'est particuliĂšrement utile pour les tĂąches qui impliquent d'attendre des ressources externes, comme des requĂȘtes de base de donnĂ©es ou des requĂȘtes rĂ©seau.
@tornado.gen.coroutine:
Le décorateur @tornado.gen.coroutine vous permet d'écrire du code asynchrone en utilisant le mot-clé yield. Cela rend le code asynchrone plus semblable au code synchrone en termes d'apparence et de comportement, améliorant la lisibilité et la maintenabilité.
import tornado.gen
import tornado.httpclient
class AsyncHandler(tornado.web.RequestHandler):
@tornado.gen.coroutine
def get(self):
http_client = tornado.httpclient.AsyncHTTPClient()
response = yield http_client.fetch("http://example.com")
self.write(response.body.decode('utf-8'))
Dans cet exemple, http_client.fetch() est une opération asynchrone qui retourne un Future. Le mot-clé yield suspend l'exécution de la coroutine jusqu'à ce que le Future soit résolu. Une fois le Future résolu, la coroutine reprend et le corps de la réponse est écrit au client.
tornado.concurrent.Future:
Un Future reprĂ©sente le rĂ©sultat d'une opĂ©ration asynchrone qui n'est peut-ĂȘtre pas encore disponible. Vous pouvez utiliser les objets Future pour enchaĂźner des opĂ©rations asynchrones et gĂ©rer les erreurs.
tornado.ioloop.IOLoop:
L'IOLoop est le cĆur du moteur asynchrone de Tornado. Il surveille les descripteurs de fichiers et les sockets pour les Ă©vĂ©nements et les distribue aux gestionnaires appropriĂ©s. En gĂ©nĂ©ral, vous n'avez pas besoin d'interagir directement avec l'IOLoop, mais il est important de comprendre son rĂŽle dans la gestion des opĂ©rations asynchrones.
WebSockets
Tornado offre un excellent support pour les WebSockets, permettant une communication en temps réel entre le serveur et les clients. Les WebSockets sont idéaux pour les applications qui nécessitent une communication bidirectionnelle à faible latence, comme les applications de chat, les jeux en ligne et les tableaux de bord en temps réel.
Créer un Gestionnaire WebSocket :
Pour créer un gestionnaire WebSocket, héritez de la classe tornado.websocket.WebSocketHandler et implémentez les méthodes suivantes :
open(): Appelé lorsqu'une nouvelle connexion WebSocket est établie.on_message(message): Appelé lorsqu'un message est reçu du client.on_close(): Appelé lorsque la connexion WebSocket est fermée.
import tornado.websocket
class WebSocketHandler(tornado.websocket.WebSocketHandler):
def open(self):
print("WebSocket ouvert")
def on_message(self, message):
self.write_message(f"Vous avez envoyé : {message}")
def on_close(self):
print("WebSocket fermé")
def check_origin(self, origin):
return True # Activer les connexions WebSocket cross-origin
Intégrer les WebSockets dans Votre Application :
Ajoutez le gestionnaire WebSocket Ă la configuration de routage de votre application :
app = tornado.web.Application([
(r"/ws", WebSocketHandler),
])
Implémentation CÎté Client :
CÎté client, vous pouvez utiliser JavaScript pour établir une connexion WebSocket et envoyer/recevoir des messages :
const websocket = new WebSocket("ws://localhost:8888/ws");
websocket.onopen = () => {
console.log("Connexion WebSocket établie");
websocket.send("Bonjour du client !");
};
websocket.onmessage = (event) => {
console.log("Message reçu :", event.data);
};
websocket.onclose = () => {
console.log("Connexion WebSocket fermée");
};
Authentification et Sécurité
La sécurité est un aspect critique du développement d'applications web. Tornado fournit plusieurs fonctionnalités pour vous aider à sécuriser vos applications, y compris l'authentification, l'autorisation et la protection contre les vulnérabilités web courantes.
Authentification :
L'authentification est le processus de vérification de l'identité d'un utilisateur. Tornado fournit un support intégré pour divers schémas d'authentification, notamment :
- Authentification par cookies : Stocker les informations d'identification de l'utilisateur dans des cookies.
- Authentification tierce (OAuth) : S'intégrer avec des plateformes de médias sociaux populaires comme Google, Facebook et Twitter.
- ClĂ©s d'API : Utiliser des clĂ©s d'API pour authentifier les requĂȘtes API.
Autorisation :
L'autorisation est le processus qui consiste Ă dĂ©terminer si un utilisateur a la permission d'accĂ©der Ă une ressource particuliĂšre. Vous pouvez implĂ©menter la logique d'autorisation dans vos gestionnaires de requĂȘtes pour restreindre l'accĂšs en fonction des rĂŽles ou des permissions des utilisateurs.
Bonnes Pratiques de Sécurité :
- Protection contre le Cross-Site Scripting (XSS) : Tornado échappe automatiquement les entités HTML pour prévenir les attaques XSS. Utilisez toujours la méthode
render()pour le rendu des modĂšles et Ă©vitez de gĂ©nĂ©rer du HTML directement dans vos gestionnaires de requĂȘtes. - Protection contre le Cross-Site Request Forgery (CSRF) : Activez la protection CSRF dans les paramĂštres de votre application pour prĂ©venir les attaques CSRF.
- HTTPS : Utilisez toujours HTTPS pour chiffrer la communication entre le serveur et les clients.
- Validation des Entrées : Validez toutes les entrées utilisateur pour prévenir les attaques par injection et autres vulnérabilités.
- Audits de Sécurité Réguliers : Effectuez des audits de sécurité réguliers pour identifier et corriger les vulnérabilités potentielles.
Déploiement
Le déploiement d'une application Tornado implique plusieurs étapes, notamment la configuration d'un serveur web, la mise en place d'un gestionnaire de processus et l'optimisation des performances.
Serveur Web :
Vous pouvez dĂ©ployer Tornado derriĂšre un serveur web comme Nginx ou Apache. Le serveur web agit comme un reverse proxy, transmettant les requĂȘtes entrantes Ă l'application Tornado.
Gestionnaire de Processus :
Un gestionnaire de processus comme Supervisor ou systemd peut ĂȘtre utilisĂ© pour gĂ©rer le processus Tornado, assurant son redĂ©marrage automatique en cas de plantage.
Optimisation des Performances :
- Utiliser une Boucle d'ĂvĂ©nements PrĂȘte pour la Production : Utilisez une boucle d'Ă©vĂ©nements prĂȘte pour la production comme
uvlooppour de meilleures performances. - Activer la Compression gzip : Activez la compression gzip pour réduire la taille des réponses HTTP.
- Mettre en Cache les Fichiers Statiques : Mettez en cache les fichiers statiques pour réduire la charge sur le serveur.
- Surveiller les Performances : Surveillez les performances de votre application Ă l'aide d'outils comme New Relic ou Prometheus.
Internationalisation (i18n) et Localisation (l10n)
Lors de la crĂ©ation d'applications pour un public mondial, il est important de prendre en compte l'internationalisation (i18n) et la localisation (l10n). L'i18n est le processus de conception d'une application de maniĂšre Ă ce qu'elle puisse ĂȘtre adaptĂ©e Ă diverses langues et rĂ©gions sans modifications techniques. La l10n est le processus d'adaptation d'une application internationalisĂ©e pour une langue ou une rĂ©gion spĂ©cifique en ajoutant des composants spĂ©cifiques Ă la locale et en traduisant le texte.
Tornado et i18n/l10n
Tornado lui-mĂȘme n'a pas de bibliothĂšques i18n/l10n intĂ©grĂ©es. Cependant, vous pouvez facilement intĂ©grer des bibliothĂšques Python standard comme `gettext` ou des frameworks plus sophistiquĂ©s comme Babel pour gĂ©rer l'i18n/l10n au sein de votre application Tornado.
Exemple avec `gettext` :
1. **Configurez vos locales :** Créez des répertoires pour chaque langue que vous souhaitez prendre en charge, contenant des catalogues de messages (généralement des fichiers `.mo`).
locales/
en/LC_MESSAGES/messages.mo
fr/LC_MESSAGES/messages.mo
de/LC_MESSAGES/messages.mo
2. **Extrayez les chaĂźnes traduisibles :** Utilisez un outil comme `xgettext` pour extraire les chaĂźnes traduisibles de votre code Python dans un fichier `.po` (Portable Object). Ce fichier contiendra les chaĂźnes originales et les emplacements pour les traductions.
xgettext -d messages -o locales/messages.po votre_app_tornado.py
3. **Traduisez les chaĂźnes :** Traduisez les chaĂźnes dans les fichiers `.po` pour chaque langue.
4. **Compilez les traductions :** Compilez les fichiers `.po` en fichiers `.mo` (Machine Object) qui sont utilisés par `gettext` à l'exécution.
msgfmt locales/fr/LC_MESSAGES/messages.po -o locales/fr/LC_MESSAGES/messages.mo
5. **Intégrez dans votre application Tornado :**
import gettext
import locale
import os
import tornado.web
class BaseHandler(tornado.web.RequestHandler):
def initialize(self):
try:
locale.setlocale(locale.LC_ALL, self.get_user_locale().code)
except locale.Error:
# GĂ©rer les cas oĂč la locale n'est pas supportĂ©e par le systĂšme
print(f"Locale {self.get_user_locale().code} non supportée")
translation = gettext.translation('messages', 'locales', languages=[self.get_user_locale().code])
translation.install()
self._ = translation.gettext
def get_current_user_locale(self):
# Logique pour dĂ©terminer la locale de l'utilisateur (ex: depuis l'en-tĂȘte Accept-Language, les paramĂštres utilisateur, etc.)
# Ceci est un exemple simplifié - vous aurez besoin d'une solution plus robuste
accept_language = self.request.headers.get('Accept-Language', 'en')
return tornado.locale.get(accept_language.split(',')[0].split(';')[0])
class MainHandler(BaseHandler):
def get(self):
self.render("index.html", _=self._)
settings = {
"template_path": os.path.join(os.path.dirname(__file__), "templates"),
}
app = tornado.web.Application([
(r"/", MainHandler),
], **settings)
6. **Modifiez vos modÚles :** Utilisez la fonction `_()` (liée à `gettext.gettext`) pour marquer les chaßnes à traduire dans vos modÚles.
<h1>{{ _("Bienvenue sur notre site web !") }}</h1>
<p>{{ _("Ceci est un paragraphe traduit.") }}</p>
Considérations Importantes pour un Public Mondial :
- **Encodage des CaractĂšres :** Utilisez toujours l'encodage UTF-8 pour supporter une large gamme de caractĂšres.
- **Formatage de la Date et de l'Heure :** Utilisez un formatage de date et d'heure spĂ©cifique Ă la locale. Les fonctions `strftime` et `strptime` de Python peuvent ĂȘtre utilisĂ©es avec les paramĂštres de locale.
- **Formatage des Nombres :** Utilisez un formatage des nombres spécifique à la locale (par ex., séparateurs décimaux, séparateurs de milliers). Le module `locale` fournit des fonctions pour cela.
- **Formatage des Devises :** Utilisez un formatage de devise spécifique à la locale. Envisagez d'utiliser une bibliothÚque comme `Babel` pour une gestion plus avancée des devises.
- **Langues de Droite à Gauche (RTL) :** Prenez en charge les langues RTL comme l'arabe et l'hébreu. Cela peut impliquer d'inverser la mise en page de votre site web.
- **QualitĂ© de la Traduction :** Faites appel Ă des traducteurs professionnels pour garantir des traductions prĂ©cises et culturellement appropriĂ©es. La traduction automatique peut ĂȘtre un bon point de dĂ©part, mais elle nĂ©cessite souvent une rĂ©vision humaine.
- **Détection de la Locale Utilisateur :** Implémentez une détection de locale robuste basée sur les préférences de l'utilisateur, les paramÚtres du navigateur ou l'adresse IP. Fournissez un moyen pour les utilisateurs de sélectionner manuellement leur langue préférée.
- **Tests :** Testez minutieusement votre application avec différentes locales pour vous assurer que tout s'affiche correctement.
Sujets Avancés
Pages d'Erreur Personnalisées :
Vous pouvez personnaliser les pages d'erreur que Tornado affiche lorsqu'une erreur se produit. Cela vous permet de fournir une expérience plus conviviale et d'inclure des informations de débogage.
ParamÚtres Personnalisés :
Vous pouvez dĂ©finir des paramĂštres personnalisĂ©s dans la configuration de votre application et y accĂ©der dans vos gestionnaires de requĂȘtes. C'est utile pour stocker des paramĂštres spĂ©cifiques Ă l'application, tels que les chaĂźnes de connexion Ă la base de donnĂ©es ou les clĂ©s d'API.
Tests :
Testez minutieusement vos applications Tornado pour vous assurer qu'elles fonctionnent correctement et en toute sécurité. Utilisez des tests unitaires, des tests d'intégration et des tests de bout en bout pour couvrir tous les aspects de votre application.
Conclusion
Tornado est un framework web puissant et polyvalent, bien adapté pour créer des applications web évolutives et performantes. Son architecture asynchrone, son support des WebSockets et son API facile à utiliser en font un choix populaire pour les développeurs du monde entier. En suivant les directives et les exemples de ce guide complet, vous pouvez commencer à créer vos propres applications Tornado et tirer parti de ses nombreuses fonctionnalités.
N'oubliez pas de consulter la documentation officielle de Tornado pour les informations les plus Ă jour et les meilleures pratiques. Bon codage !